home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / Printer Status Samples next >
Encoding:
Text File  |  1996-03-20  |  16.8 KB  |  606 lines  |  [TEXT/MPS ]

  1. /*____________________________________________________
  2.  
  3.     Sample routines for sending status to the desktop
  4.     printer window, and handling user alerts.
  5.  
  6.                    Apple Computer, Inc.
  7.                   Copyright ©1991 - 1994
  8.  
  9.         5/04/94 - dmh - Verified for the f2 seed.
  10.        3/22/94 - dmh - Verified for the b4 seed.
  11.        3/22/94 - dmh - Filled out statusOwner fields!
  12.       12/20/93 - dmh - Updated for the b3 seed.
  13.         9/13/93 - dmh - Updated for the b2 seed.
  14.  
  15.     Note:  Descriptions are listed in the "Mark" menu.
  16.  
  17.     ___________________________________________________    */
  18.  
  19. // Sample code for writing status to the desktop printer window.
  20.  
  21.  
  22. #define    kTransmissionStatID                1
  23. #define    kOpeningConnectionStatIdx        8
  24.  
  25.  
  26.     anErr = GXReportStatus(kTransmissionStatID, kOpeningConnectionStatIdx);
  27.     
  28.  
  29. resource 'stat' (kTransmissionStatID, sysheap, purgeable)
  30. {
  31.     kDrvrCreatorType,
  32.     {
  33.         informationalStatus,        0,                                    kNoAlertAlertID,                "Sending part of the page…";
  34.         informationalStatus,        0,                                    kNoAlertAlertID,                "Preparing part of the page…";
  35.         userAlert,                     kChangeCarouselsDlogID,     kNoAlertAlertID,                "Please load the appropriate pen.";
  36.         informationalStatus,     0,                                 kNoAlertAlertID,                "A print test is in progress.  Please wait…";
  37.         userAlert,                     0,                                    kBadTonerCartridgeAlertID,    "The toner cartridge is improperly loaded.";
  38.         informationalStatus,     0,                                    kNoAlertAlertID,                "Printing the page.";
  39.         userAlert,                     0,                                    kCantFindPrinterAlertID,    "Trying to locate the printer…";
  40.         openConnectionStatus,     0,                                    kNoAlertAlertID,                "Opening a connection to the printer…";
  41.     }
  42. };
  43.  
  44.  
  45.  
  46. //        Alerts GX already handles -
  47. //
  48. //            manual feed
  49. //            paper jam
  50. //            failed to print
  51. //            printer ready
  52. //            out of paper
  53. //            no paper tray
  54. //            alert me before printing
  55. //            alert me after printing
  56. //
  57. //        PrintingDrivers.h has constants you need for this    
  58.  
  59.  
  60.  
  61. //    Sample code for "Manual Feed Alert" - one that we help you with
  62.  
  63. //
  64. //
  65. //        DoManualFeedDialog
  66. //
  67. //        This function will present a manual feed dialog to the user.  In this
  68. //        example we have a printer that is smart enough to know if the user has
  69. //        placed paper in the manual feed slot.  This printer will also allow the
  70. //        user to decide to switch to automatic feed at dialog time.
  71. //
  72. //        The driver must allocate a status record with a buffer that will contain
  73. //        the gxManualFeedRecord.  This record contains the name of the papertype
  74. //        which needs to be fed.  This will be displayed in the dialog.  The record
  75. //        also contains a boolean that tells the printing manager whether the dialog should 
  76. //        contain the automatic feed button.
  77. //
  78. //        The driver fills in the statResId and statResIndex fields of the status record
  79. //        to indicate that the desired stat resource belongs to the universal driver and
  80. //        the particular alert is for manual feed.  The papertype name is filled in.
  81. //
  82. //        The driver then calls GXAlertTheUser which will display the dialog.  The driver
  83. //        continues to call GXAlertTheUser until an error is returned or the user selects
  84. //        one of the buttons in the dialog ( ok, cancel or autoFeed ).  Because this printer
  85. //        is so smart, it can tell if the user fed paper without having the user select
  86. //        any button.  The driver checks for this case in the loop.  If this case is detected,
  87. //        the driver makes a last call to GXAlertTheUser to tell the Printing Manager to
  88. //        remove the dialog.  Once the user selects any button in the dialog, the dialog
  89. //        is automatically dismissed. The dialog is also dismissed when any error is returned.
  90. //
  91. //        The driver examines the dialogResult field of the status record to see which
  92. //        option the user has selected.
  93. //
  94. //        Before exiting the routine, the status record pointer is disposed.
  95. //
  96. //        Note that the CheckToSeeIfPaperWasFed routine must be supplied by the driver.
  97. //
  98. //
  99.  
  100.  
  101. OSErr    DoManualFeedDialog()
  102. {
  103.     OSErr                anErr;
  104.     gxStatusRecord    *pStatus;    
  105.     
  106. // allocate the status record
  107.  
  108.     pStatus = (Ptr) NewPtrClear(sizeof(gxStatusRecord) + gxManualFeedStatusBufferSize);
  109.     anErr = MemError();
  110.  
  111.     if (anErr == noErr ) {
  112.  
  113.         gxManualFeedRecord    *mfeedInfo;
  114.  
  115.         pStatus->statusOwner        = kDrvrCreatorType;
  116.         pStatus->statResId         = gxUnivAlertStatusResourceId;
  117.         pStatus->statResIndex     = gxUnivManualFeedIndex;
  118.         pStatus->bufferLen        = gxManualFeedStatusBufferSize;
  119.  
  120.         mfeedInfo = (gxManualFeedRecord *) &pStatus->statusBuffer;
  121.         mfeedInfo->canAutoFeed = true;
  122.         GXGetPaperTypeName(thePaperType, mfeedInfo->paperTypeName);
  123.  
  124.  
  125. // Tell the Printing Manager to display the manual feed alert
  126.  
  127.         do
  128.         {
  129.  
  130.             anErr = GXAlertTheUser(pStatus);
  131.  
  132.             // see if the user has loaded the paper
  133.  
  134.             if ((anErr == noErr) && (pStatus->dialogResult == nil)) {
  135.     
  136.                 Boolean    userFedPaper;    
  137.                 
  138.                 userFedPaper = CheckToSeeIfPaperWasFed();
  139.                 if (userFedPaper) {
  140.                     pStatus->statResIndex    = gxUnivPrinterReadyIndex;
  141.                     anErr = GXAlertTheUser(pStatus);
  142.                     pStatus->dialogResult = ok;
  143.                     
  144.                     }
  145.                 }
  146.                 
  147.             } while ((pStatus->dialogResult == nil) &&  (anErr == noErr));
  148.  
  149.  
  150. // act on the dialog result
  151.  
  152.         if (anErr == noErr) {
  153.         
  154.             switch (pStatus->dialogResult) {
  155.                 
  156.                 gxOKSelected:            PrintThePageManually();
  157.                                             break;
  158.                                 
  159.                 gxCancelSelected:        anErr = gxPrUserAbortErr;
  160.                                             break;
  161.                                 
  162.                 gxAutoFeedButtonId:    PrintThePageAutomatically();
  163.                                             break;
  164.                 }
  165.             }
  166.         DisposePtr( pStatus );
  167.         }
  168.     return( anErr );
  169. }
  170.  
  171.  
  172.  
  173. // Sample code for "Printer Not Responding" - one you do yourself
  174.  
  175. //
  176. //
  177. //        HandleOpenConnection
  178. //
  179. //        This function will attempt to open a connection to the printer.  If it fails
  180. //        it will send an alert to the user.
  181. //
  182. //        The driver supplies a 'cool' Alert resource.  The stat resource referenced by
  183. //        the status record that the driver builds will reference this cool alert.
  184. //        Note that the cool alert has place holders for strings.  The printing manager
  185. //        will fill these strings in with the name of the printer and the document. This
  186. //        is the default behavior when a cool alert is referenced with these placeholders.
  187. //        !0 will be replaced with the printer name.  !1 will be replaced with the document
  188. //        name.  !2 will be replaced with any papertype name sent.
  189. //
  190. //        The driver must allocate a status record with a default buffer that will be used
  191. //        internally by the printing manager.
  192. //
  193. //        The driver fills in the statResId and statResIndex fields of the status record
  194. //        to indicate that the desired stat resource belongs to the driver and
  195. //        the particular alert informs the user that the printer cannot be found.
  196. //
  197. //        The driver then calls GXAlertTheUser which will display the dialog.  The driver
  198. //        continues to call GXAlertTheUser until an error is returned or the user selects
  199. //        the Abort button.  The driver continues to look for the printer while the
  200. //        alert is up.  If the printer is found, the driver calls GXAlertTheUser a final
  201. //        time to remove the dialog.  If the user selects the Abort button, the dialog
  202. //        is automatically dismissed.   The dialog is also dismissed when any error is returned.
  203. //
  204. //        The driver examines the dialogResult field of the status record to see which
  205. //        option the user has selected.
  206. //
  207. //        Before exiting the routine, the status record pointer is disposed.
  208. //
  209. //        Note that the TryToOpenConnection routine must be supplied by the driver.
  210. //
  211. //
  212.  
  213. #define    kTransmissionStatID            1
  214. #define    kCantFindPrinterStatIdx        7
  215.  
  216.  
  217. OSErr    HandleOpenConnection()
  218. {
  219.     OSErr                anErr;
  220.     gxStatusRecord    *pStatus;    
  221.     
  222.     
  223.     anErr = TryToOpenConnection();
  224.  
  225.     if (anErr == gxAioCantFindDevice)             //    T => Can't locate device; tell user to turn it on
  226.     {
  227.         // Now we set-up to alert the user that the printer cannot be found
  228.         // Allocate a status record large enough to handle status with the largest 
  229.         // buffer size. 
  230.     
  231.         pStatus = (Ptr) NewPtrClear(sizeof(gxStatusRecord) + gxDefaultStatusBufferSize);
  232.         anErr = MemError();
  233.         if (anErr == noErr) {
  234.     
  235.             // Initialize the appropriate fields within the status record 
  236.             
  237.             pStatus->statusOwner        = kDrvrCreatorType;
  238.             pStatus->statResId         = kTransmissionStatID;
  239.             pStatus->statResIndex     = kCantFindPrinterStatIdx;
  240.             pStatus->bufferLen         = gxDefaultStatusBufferSize;
  241.     
  242.             // Now display the alert to the user
  243.             do
  244.             {    
  245.                 anErr = GXAlertTheUser(pStatus);
  246.                 if ((anErr == noErr) && (pStatus->dialogResult == nil))
  247.                 {                // Try looking for the device again
  248.                     anErr = TryToOpenConnection();
  249.                 }
  250.             }
  251.             while ( (anErr == gxAioCantFindDevice) && (pStatus->dialogResult == nil) );
  252.             
  253.             // If the user dismissed the dialog, we are to abort the job
  254.             if (pStatus->dialogResult != nil)
  255.                 anErr = gxPrUserAbortErr;
  256.             
  257.             else        // another error (possible timeout) or success
  258.             {
  259.                 pStatus->statResId      =    gxUnivAlertStatusResourceId;
  260.                 pStatus->statResIndex =    gxUnivPrinterReadyIndex;
  261.                 GXAlertTheUser(pStatus);     // Tell GX to remove the alert
  262.             }
  263.             
  264.             // Kill the status pointer
  265.             DisposPtr((Ptr) pStatus);
  266.             }
  267.     }
  268.     
  269.     return( anErr );
  270. }
  271.  
  272.  
  273. resource 'plrt' (kCantFindPrinterAlertID, sysheap, purgeable)
  274. {                                                                    //    The printer can't be found on the 
  275.                                                                     //     SCSI bus
  276.     printingStatus,                            // version
  277.     cautionIcon,                            // icon id
  278.     defaultSystemSize,
  279.     defaultAction,                            // the default label
  280.     noCancelTitle,                            // no cancel
  281.     "The document !1 cannot be printed, because the printer "
  282.      "!0 cannot be found.  To continue printing, please make "
  283.     "sure the printer is "
  284.     "properly connected and turned on.  If you wish "    
  285.     "to cancel printing, please click Abort Job.",
  286.      "Abort Job",                                // action label
  287.     "",                                            // button label 2
  288.     "",                                            // button label 3
  289.     " "                                            // font name
  290. };
  291.  
  292.  
  293.  
  294. // Sample code for "Plotter Carousel Change" Alert - one you do yourself
  295.  
  296. //
  297. //
  298. //        HandleCarouselChange
  299. //
  300. //        This function will initiate a dialog with the user asking the user to
  301. //        place the appropriate carousel in the plotter.
  302. //
  303. //        The dialog that will be displayed to the user is not a cool alert.  The
  304. //        driver needs to supply parts of the dialog dynamically - the name of the
  305. //        carousel and the names of the pens it hopes to find there.  These names
  306. //        are stored in the buffer in the status record.  The driver allocates the
  307. //        status record with a buffer larger enough to hold these strings.  It then
  308. //        fills in the strings.
  309. //
  310. //        The driver fills in the statResId and statResIndex fields of the status record
  311. //        to indicate that the desired stat resource belongs to the driver and
  312. //        the particular alert informs the user that the print carousel needs to be changed.
  313. //
  314. //        The driver then calls GXAlertTheUser which will display the dialog.  The driver
  315. //        continues to call GXAlertTheUser until an error is returned or the user selects
  316. //        the Abort one of the buttons in the dialog.
  317. //
  318. //        In order to conduct this dialog, the driver must override 2 messages - 
  319. //            InitializeStatusAlert - to create the dialog and
  320. //            HandleAlertEvent         - to handle dialog events
  321. //
  322. //        The driver examines the dialogResult field of the status record to see which
  323. //        option the user has selected.
  324. //
  325. //        Before exiting the routine, the status record pointer is disposed.
  326. //
  327. //        Note that the FillInCarouselInfo routine must be supplied by the driver.
  328. //
  329. //
  330.  
  331. #define    kTransmissionStatID            1
  332. #define    kLoadPenIdx                        3
  333.  
  334. typedef struct {
  335.     Str31        carouselName;
  336.     Str15        penName1;                
  337.     Str15        penName2;                
  338.     Str15        penName3;                
  339.     Str15        penName4;                
  340.     } CarouselInfo;
  341.  
  342. OSErr    HandleCarouselChange()
  343. {
  344.     OSErr                anErr;
  345.     gxStatusRecord    *pStatus;    
  346.     
  347.     
  348.     // Allocate a status record large enough to handle status with the a
  349.     // buffer to hold the CarouselInfo structure. 
  350.  
  351.     pStatus = (Ptr) NewPtrClear(sizeof(gxStatusRecord) + sizeof( CarouselInfo ));
  352.     anErr = MemError();
  353.     if (anErr == noErr) {
  354.  
  355.  
  356.         // fill in the status buffer will carousel name and pen names
  357.         
  358.         FillInCarouselInfo( pStatus );
  359.     
  360.         // Initialize the appropriate fields within the status record 
  361.         
  362.         pStatus->statusOwner        = kDrvrCreatorType;
  363.         pStatus->statResId         = kTransmissionStatID;
  364.         pStatus->statResIndex     = kLoadPenIdx;
  365.         pStatus->bufferLen         = sizeof( CarouselInfo );
  366.  
  367.         // Now display the alert to the user
  368.         do
  369.         {    
  370.             anErr = GXAlertTheUser(pStatus);
  371.         }
  372.         while ( (anErr == noErr) && (pStatus->dialogResult == nil) );
  373.         
  374.         // Act on result
  375.  
  376.         if (pStatus->dialogResult != nil) {
  377.         
  378.             switch (pStatus->dialogResult)
  379.             
  380.             ok:                HandleChange();
  381.                                 break;
  382.  
  383.             cancel:            HandleCancel();
  384.                                 break;
  385.                                 
  386.             holdRequest:    HandleHold();
  387.                                 break;
  388.  
  389.             }
  390.         
  391.         // Kill the status pointer
  392.         DisposPtr((Ptr) pStatus);
  393.         }
  394.     
  395.     return( anErr );
  396. }
  397.  
  398.  
  399. //
  400. //        MyInitializeStatusAlert
  401. //
  402. // This routine is called when overriding InitializeStatusAlert
  403. //
  404. //    Since this is a message, the first thing the driver does is see if this
  405. // message is intended for the driver by checking the owner field in the
  406. // status record.  If the owner is not the driver, the message is forwarded.
  407. //
  408. // In the case that the driver is the owner, the driver checks the status id
  409. // to see which alert needs to be created.  The driver calls GetNewDialog on
  410. // the appropriate resource and then calls a routine to dynamically fill in
  411. // the static text strings in the dialog.  These strings are stored in the
  412. // status buffer in the status record.
  413. //
  414. // On the return, the Finder will display the dialog referenced through the
  415. // pDialog parameter.
  416. //
  417. //
  418.  
  419. OSErr    MyInitializeStatusAlert( gxStatusRecordPtr pStatus, DialogPtr *pDialog )
  420. {
  421.     OSErr        anErr = noErr;
  422.     
  423.     // first see if this message is for you
  424.     
  425.     if (pStatus->statusOwner == kDrvrCreatorType) {
  426.  
  427.         if (pStatus->statusId == kChangeCarouselsDlogID) {
  428.  
  429.             *pDialog = GetNewDialog( kChangeCarouselsDlogID, nil, (WindowPtr)-1);
  430.             if (*pDialog == nil)
  431.                 anErr = resNotFound;
  432.             else
  433.                 FillInDialogStrings( pStatus, pDialog );
  434.  
  435.  
  436.  
  437.             }
  438.         else...
  439.  
  440.  
  441.         }
  442.  
  443.     else                                                                    // it belongs to someone else
  444.         Forward_GXInitializeStatusAlert( pStatus, pDialog );
  445.         
  446.     return( anErr );
  447. }
  448.  
  449.  
  450. //
  451. //        MyHandleAlertEvent
  452. //
  453. // This routine is called when overriding HandleAlertEvent
  454. //
  455. //    Since this is a message, the first thing the driver does is see if this
  456. // message is intended for the driver by checking the owner field in the
  457. // status record.  If the owner is not the driver, the message is forwarded.
  458. //
  459. // In the case that the driver is the owner, the driver checks the status id
  460. // to see which alert is being conducted.  The driver then examines the event
  461. // for the alert.  If the user dismisses the dialog by selecting a dialog 
  462. // button, this result is recorded in the status record.
  463. //
  464. // On the return, the Finder will dismiss the dialog if the dialogResult field
  465. // is not nil.  The dialog is also dismissed when any error is returned.
  466. //
  467. // Note that a driver may use the status buffer for any purpose it needs to.  For
  468. // example, if the driver needed more information returned from this dialog, it
  469. // could be stored in the buffer.
  470. //
  471. // Note that the HandleCarouselDialogEvent is supplied by the driver.
  472. //
  473. //
  474. OSErr    MyHandleAlertEvent( gxStatusRecordPtr pStatus, DialogPtr *pDialog,
  475.                                   EventRecord *theEvent, short *itemHit )
  476. {
  477.     OSErr        anErr = noErr;
  478.     
  479.     // first see if this message is for you
  480.     
  481.     if (pStatus->statusOwner == kDrvrCreatorType) {
  482.  
  483.         if (pStatus->statusId == kChangeCarouselsDlogID) {
  484.  
  485.             HandleCarouselDialogEvent( pDialog, theEvent, itemHit );
  486.             pStatus->dialogResult = *itemHit;
  487.  
  488.  
  489.             }
  490.         else...
  491.  
  492.  
  493.         }
  494.  
  495.     else                                                // it belongs to someone else
  496.         Forward_GXHandleAlertEvent( pStatus, pDialog, theEvent, itemHit );
  497.         
  498.     return( anErr );
  499. }
  500.  
  501.  
  502. #define SystemSevenOrLater        true
  503.  
  504. resource 'DLOG' (kChangeCarouselsDlogID, sysheap, purgeable) {
  505.     {50, 10, 310, 440},
  506.     movableDBoxProc,
  507.     invisible,
  508.     noGoAway,
  509.     0x0,
  510.     kChangeCarouselsDlogID,
  511.     "",
  512.     centerMainScreen
  513. };
  514.  
  515.  
  516. resource 'DITL' (kChangeCarouselsDlogID, sysheap, purgeable) {
  517.     {    /* array DITLarray: 14 elements */
  518.         /* [1] */
  519.         {234, 335, 254, 415},
  520.         Button {
  521.             enabled,
  522.             "Continue"
  523.         },
  524.         /* [2] */
  525.         {234, 178, 254, 320},
  526.         Button {
  527.             enabled,
  528.             "Cancel print request"
  529.         },
  530.         /* [3] */
  531.         {234, 10, 254, 165},
  532.         Button {
  533.             enabled,
  534.             "Place request on Hold"
  535.         },
  536.         /* [4] */
  537.         {20, 60, 68, 410},
  538.         StaticText {
  539.             disabled,
  540.             "Please place the ^0 carousel in the plotter.  Make sure the "
  541.             "plotter is finished with the current set of pens before "
  542.             "making the change."
  543.         },
  544.         /* [5] */                    
  545.         {105, 30, 198, 207},            //    Rectangle that bounds the image of the carousel
  546.         UserItem {
  547.             disabled
  548.         },
  549.         /* [6] */
  550.         {90, 215, 106, 235},
  551.         StaticText {
  552.             enabled,
  553.             "1."
  554.         },
  555.         /* [7] */
  556.         {90, 240, 106, 400},            //    Pen #1 name
  557.         StaticText {
  558.             enabled,
  559.             ""
  560.         },
  561.         /* [8] */
  562.         {106, 215, 122, 235},
  563.         StaticText {
  564.             enabled,
  565.             "2."
  566.         },
  567.         /* [9] */
  568.         {106, 240, 122, 400},        //    Pen #2 name
  569.         StaticText {
  570.             enabled,
  571.             ""
  572.         },
  573.         /* [10] */
  574.         {122, 215, 138, 235},
  575.         StaticText {
  576.             enabled,
  577.             "3."
  578.         },
  579.         /* [11] */
  580.         {122, 240, 138, 400},        //    Pen #3 name
  581.         StaticText {
  582.             enabled,
  583.             ""
  584.         },
  585.         /* [12] */
  586.         {138, 215, 154, 235},
  587.         StaticText {
  588.             enabled,
  589.             "4."
  590.         },
  591.         /* [13] */
  592.         {138, 240, 154, 400},        //    Pen #4 name
  593.         StaticText {
  594.             enabled,
  595.             ""
  596.         },
  597.         /* [14] */
  598.         {20, 9, 52, 41},                //    Stop icon
  599.         Icon {
  600.             disabled,
  601.             2
  602.         },
  603.     }
  604. };
  605.  
  606.